package com.ruoyi.project.setting.security.service;

import cn.hutool.core.util.IdUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.dyun.tool.jwt.constant.UserConstants;
import com.dyun.tool.jwt.utils.JWTUtil;
import com.ruoyi.common.enums.BaseStatusEnum;
import com.ruoyi.framework.utils.AddressUtils;
import com.ruoyi.project.monitor.entity.SysLoginLog;
import com.ruoyi.project.monitor.syslog.SysLogUtils;
import com.ruoyi.project.setting.security.LoginUser;
import com.ruoyi.project.system.entity.SysUser;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.WebUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录校验方法
 *
 * @author dy
 */
@Slf4j
@Component
public class SysLoginService {

    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private SysPermissionService permissionService;

    public Map<String, Object> login(SysUser user) {
        String redisToken = IdUtil.fastUUID();

        // 生成jwt token
        Map<String, Object> userMap = new HashMap<>(16);
        userMap.put(UserConstants.USERID, user.getId());
        userMap.put(UserConstants.PRINCIPAL, redisToken);
        String token = JWTUtil.sign(userMap);

        // 该方法不是必须的，可以去除
        // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
        authenticationManager
                .authenticate(new UsernamePasswordAuthenticationToken(token, token));

        LoginUser loginUser = initLoginUser(redisToken, user);
        recordLoginLog(loginUser, BaseStatusEnum.DB_STATUS_SUCCESS.getStatus(), "登陆成功");

        Map<String, Object> map = new HashMap<>(16);
        map.put("token", token);
        map.put("loginUser", loginUser.toLoginUserVO());
        return map;
    }

    /**
     * 更新LoginUser
     */
    public LoginUser initLoginUser(String redisToken, SysUser sysUser) {
        LoginUser loginUser = new LoginUser();
        loginUser.setSysUser(sysUser);
        loginUser.setUserId(sysUser.getId());
        loginUser.setToken(redisToken);

        setUserAgent(loginUser);

        permissionService.getSetRoles(loginUser);
        permissionService.getSetPermissions(loginUser);
        tokenService.setLoginUser(loginUser);

        return loginUser;
    }

    /**
     * 设置用户代理信息
     *
     * @param loginUser 登录信息
     */
    private void setUserAgent(LoginUser loginUser) {
        UserAgent ua = UserAgentUtil.parse(WebUtil.getRequest().getHeader("User-Agent"));
        String ip = WebUtil.getIP();
        loginUser.setIpaddr(ip);
        loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
        loginUser.setBrowser(ua.getBrowser().toString());
        loginUser.setOs(ua.getOs().toString());
    }

    public static void recordLoginLog(LoginUser loginUser, Integer status, String msg) {
        SysLoginLog sysLoginLog = new SysLoginLog();
        sysLoginLog.setOperTime(new Date());
        sysLoginLog.setUserType(loginUser.getSysUser().getSocialCode());
        sysLoginLog.setUserName(loginUser.getSysUser().getUserName());
        sysLoginLog.setIpaddr(loginUser.getIpaddr());
        sysLoginLog.setLoginLocation(loginUser.getLoginLocation());
        sysLoginLog.setBrowser(loginUser.getBrowser());
        sysLoginLog.setOs(loginUser.getOs());

        sysLoginLog.setStatus(status);
        sysLoginLog.setMsg(msg);
        SysLogUtils.me().recordLoginLog(sysLoginLog);
    }

}
